var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var fs = require('fs');
var port = 8080;
var tournamentAdminList = [];
var tournamentNameList = [];
var clients = [];
var count = 0;

//ServerConfig
/*
server.listen(port);
app.configure(function () {
    app.use(express.static(__dirname + '/public'));
});

*/
server.listen(port, function () {
    console.log('Der Server läuft nun unter http://127.0.0.1:' + port + '/');
});
app.use(express.static(__dirname + '/public'));
app.get('/', function (req, res) {
    res.sendfile(__dirname + '/public/index.html');
});
// Websocket
io.on('connection', socketHandling);

function socketHandling(socket) {
    var client = {};

    socket.on('register', function (uuid) {
        if (!(client = clients[uuid])) { // New client
            count++;
            console.log('> New client - Total: ' + count);
            client = clients[uuid] = {
                uuid: uuid,
                tabs: 0,
                tournamentID: -1,
                isAdmin: false
            };
            // Send new counter to all connected clients
            socket.emit('newClient');

            io.sockets.emit('stats', count);
        } else {
            // Check for multiple browser tabs opened
            if (!client.disconnected) {
                console.log("ACHTUNG, HIER SOLLTE NICHT REIN GESPRUNGEN WERDEN!!");
                client.tabs++;
                socket.disconnect();
            }
        }

        // Keep client connected if a refresh occur before timeout
        if (client.disconnected) {
            clearTimeout(client.timeout);
            client.disconnected = false;
            socket.emit('oldClient');
        }

        socket.emit('stats', count);
        if (client.tournamentID == -1) {
            initNewClient();
        } else if (client.isAdmin) {
            var tournamentAdmin = null;
            for (var i = 0; i < tournamentAdminList.length && tournamentAdmin == null; i++) {
                if (client.tournamentID == tournamentAdminList[i].id) {
                    tournamentAdmin = tournamentAdminList[i];
                }
            }
            if (tournamentAdmin != null) {
                adminTournament(client.tournamentID, tournamentAdmin.tournament);
            }
        } else {
            joinTournament(client.tournamentID);
        }
        clients[uuid] = client;
    });

    socket.on('disconnect', function (type) {
        // Don't disconnect client in-game
        //if (type == 'booted' && client.tabs > 0)
        //    return;

        client.disconnected = true;

        client.timeout = setTimeout(function () {
            if (client.disconnected) {
                delete clients[client.uuid];
                count--;
                console.log('> Client disconnected - Total: ' + count);
                // Send new counter to all connected clients
                io.sockets.emit('stats', count);
            }
        }, 2000)
    });

    var initNewClient = function () {
        console.log("Aufruf: initNewClient");
        //Listener Eitragen
        refreshListener();
        //wird in die Gruppe der Übersicht eingetragen
        socket.join('lounge');
        // Ihm wird die aktuelle Liste aller laufenden Turniere zur Verfügung gestellt
        socket.emit('initTournamentList', tournamentNameList);
    }

    var joinTournament = function (tournamentID) {
        console.log("Aufruf: joinTournament");
        if (tournamentID != null &&
            tournamentID != undefined &&
            tournamentID > -1) {
            var tournament = null; //Finde das torunament mit der gegebenen TournamentID
            for (var i = 0; i < tournamentAdminList.length && tournament == null; i++) {
                if (tournamentID == tournamentAdminList[i].id) {
                    tournament = tournamentAdminList[i].tournament;
                }
            }
            if (tournament != null) {
                //Listener anpassen
                client.tournamentID = tournamentID;
                refreshListener();

                console.log("--> der ID " + tournamentID);
                //Sicherstellen dass nur ein zusätzlicher raum betreten wird
                if (socket.rooms.length > 1) {
                    socket.leave(socket.rooms.pop());
                }
                //Raum beitreten
                socket.join(tournamentID);
                socket.emit('initTournament', tournament);
            } else {
                socket.emit('errorMessage', {
                    message: 'Serverfehler: Turnier nicht gefunden.'
                });
                console.log("Turnier nicht gefunden");
            }
        } else {
            socket.emit('errorMessage', {
                message: 'Fehler'
            });
            console.log("Fehlerhafte Daten");
        }
    }

    var adminExistingTournament = function (data) {
        console.log("Aufruf: adminexisting Tournmanet");
        if (data.tournamentID != null &&
            data.tournamentID != undefined &&
            data.tournamentID > -1) {
            //Tournier herraussuchen und Passwort überprüfen.
            var tournamentAdmin = null;
            for (var i = 0; i < tournamentAdminList.length && tournamentAdmin == null; i++) {
                if (data.tournamentID == tournamentAdminList[i].id) {
                    tournamentAdmin = tournamentAdminList[i];
                }
            }
            if (tournamentAdmin != null) {
                if (tournamentAdmin.adminPass == data.adminPass) {
                    adminTournament(data.tournamentID, tournamentAdmin.tournament);
                } else {
                    socket.emit('errorMessage', {
                        message: "Es wurde das Falsche Admin-Passwort Eingegeben"
                    });
                }
            } else {
                socket.emit('errorMessage', {
                    message: 'Serverfehler: Turnier nicht gefunden.'
                });
                console.log("Turnier nicht gefunden.");

            }
        } else {
            socket.emit('errorMessage', {
                message: 'Fehler'
            });
            console.log("Fehlerhafte Daten als Input");
        }
    }

    var adminNewTournament = function (data) {
        console.log("Aufruf: admin new tournament");
        if (data.tournamentName != null &&
            data.adminPass != null &&
            data.competitors != null &&
            data.competitors.constructor.toString().indexOf("Array") > -1 &&
            data.competitors.length > 4) {
            //Neues Turnier anlegen und speichern, adminpass und name speichern
            var tournamentAdmin = new TournamentAdmin(data.tournamentName, data.competitors, data.adminPass);
            tournamentAdminList.push(tournamentAdmin);
            tournamentNameList.push({
                id: tournamentAdmin.id,
                name: tournamentAdmin.tournament.name
            });
            io.sockets.in('lounge').emit('refreshTournamentList', {
                id: tournamentAdmin.id,
                name: tournamentAdmin.tournament.name
            });
            adminTournament(tournamentAdmin.id, tournamentAdmin.tournament);
            console.log("Turnier ID: " + tournamentAdmin);
        } else {
            socket.emit('errorMessage', {
                message: 'Bitte die Eingabe Prüfen. Die Teilnehmernamen müssen mit ";" getrennt eingegeben werden. Eine Mindestanzahl von 4 ist erforderlich'
            });
            console.log("Fehlerhafte Daten als Input");
        }
    }

    var adminTournament = function (tournamentID, tournamentOnStart) {
        //Listener anpassen
        client.tournamentID = tournamentID;
        client.isAdmin = true;
        refreshListener();
        socket.on('setScoreInGame', setScoreInGame);
        socket.on('quitTournament', quitTournament);
        //Sicherstellen dass nur ein zusätzlicher raum betreten wird
        if (socket.rooms.length > 1) {
            socket.leave(socket.rooms.pop());
        }
        //Raum beitreten
        socket.join(tournamentID);
        socket.emit('initTournament', tournamentOnStart);
        socket.emit('confirmTournamentAdmin');

        function setScoreInGame(data) {
            console.log("Aufruf: Set Score in Game");
            if (data.gameIndex != null && data.gameIndex != undefined &&
                data.score1 != null && data.score1 != undefined &&
                data.score2 != null && data.score2 != undefined) {
                //ergebnis setzen über funktion, Turnier vorher raussuchen und danach speichern
                var tournament = null; //Finde das torunament mit der gegebenen TournamentID
                for (var i = 0; i < tournamentAdminList.length && tournament == null; i++) {
                    if (tournamentID == tournamentAdminList[i].id) {
                        tournament = tournamentAdminList[i].tournament;
                    }
                }
                if (tournament.gameList[data.gameIndex].player1 > -1 &&
                    tournament.gameList[data.gameIndex].player2 > -1) {
                    var changes = Tournament.setResAndGetChanges(data.gameIndex, data.score1, data.score2, tournament);
                    if (changes != false) {
                        //Turnier zurücksenden
                        //io.sockets.in(tournamentID).emit('initTournament', tournament);
                        //Spiele die geändert wurden senden
                        io.sockets.in(tournamentID).emit('changedGames', changes);
                        //ChangeEvent senden
                        var d = new Date();
                        io.sockets.in(tournamentID).emit('changeEvent', {
                            date: d.toLocaleTimeString(),
                            spiel: data.gameIndex,
                            winner: tournament.competitorsList[Game.getWinner(tournament.gameList[data.gameIndex])],
                            res: data.score1 + ' : ' + data.score2
                        });
                    } else {
                        console.log("Fehler beim speichern des Turniers");
                        socket.emit('errorMessage', {
                            message: 'Fehler beim Setzen des Ergebnisses'
                        });
                    }
                } else {
                    console.log("Falsche Eingabe: Spiele mit Freilosen können nicht bearbeitet werden.");
                    socket.emit('errorMessage', {
                        message: 'Falsche Eingabe: Spiele mit Freilosen können nicht bearbeitet werden.'
                    });
                }
            } else {
                console.log("Fehlerhafte Daten als Input");
                socket.emit('errorMessage', {
                    message: 'Bitte die Eingabe überprüfen. Keine negativen Ergebnisse zugelassen. Kein Gleichstand ist erlaubt. Spiele die ein Freilos enthalten können nicht bearbeitet werden.'
                });
            }
        }

        function quitTournament() {
            console.log("Aufruf: Quit Tournament");
            client.tournamentID = -1;
            client.isAdmin = false;
            refreshListener();
            for (var i = 0; i < tournamentAdminList.length; i++) {
                if (tournamentID == tournamentAdminList[i].id) {
                    tournamentAdminList.splice(i, 1);
                }
            }
            for (var i = 0; i < tournamentNameList.length; i++) {
                if (tournamentID == tournamentNameList[i].id) {
                    tournamentNameList.splice(i, 1);
                }
            }
            //Zuschauer und Admin rauswerfen rauswerfen
            io.sockets.in(tournamentID).emit('gameover');
            if (socket.rooms.length > 1) {
                socket.leave(socket.rooms.pop());
            }
            socket.emit('initTournamentList', tournamentNameList);
            io.sockets.in('lounge').emit('refreshTournamentList', {id: tournamentID});
            socket.join('lounge');
        }
    }

    var leaveTournament = function () {
        console.log("Aufruf: Leave Tournament");
        //Listeneranpassen
        client.tournamentID = -1;
        client.isAdmin = false;
        refreshListener();
        //socket aus gruppe austragen
        if (socket.rooms.length > 1) {
            socket.leave(socket.rooms.pop());
        }
        //in gruppe lounge eintragen
        socket.join('lounge');
        socket.emit('initTournamentList', tournamentNameList);
    }

    var refreshListener = function () {
        if (client.tournamentID == -1) {
            //Listener
            socket.removeAllListeners('quitTournament');
            socket.removeAllListeners('setScoreInGame');
            socket.removeAllListeners('leaveTournament');
            socket.on('joinTournament', joinTournament);
            socket.on('adminExistingTournament', adminExistingTournament);
            socket.on('adminNewTournament', adminNewTournament);
        } else {
            //Listener
            socket.removeAllListeners('joinTournament');
            socket.removeAllListeners('adminExistingTournament');
            socket.removeAllListeners('adminNewTournament');
            socket.on('leaveTournament', leaveTournament);
        }
    }

}

var idSetter = 0;
//Klasse: TurninerAdministration
function TournamentAdmin(tournamentName, competitors, adminPass) {
    this.id = idSetter;
    idSetter++;
    this.adminPass = adminPass;
    this.tournament = new Tournament(competitors, tournamentName);
}

/*  Klasse: Player 
    Die Klasse beinhaltet zur Zeit nur den Namen des Spielers
    Über den Konstruktur wird ein Spieler angelegt.
    Input: name: String
    Output: Spieler: Player
*/

function Player(name) {
    this.name = name;
}

/* Klasse: Game
    beinhaltet folgende Attribute:
        player1: Player
        player2: player
        scorePlayer1: int
        scorePlayer2: int
        source1: Source (Herkunt von Spieler 1)
        source2: Source (Herkunft von Spieler 2)
    Über den Konstruktur wird ein neues Spiel erstellt, dabei werden die beiden Spieler mitgegeben
    Input:  player1: Spieler
            player2: Spieler
    Output: Spiel: Game
*/

function Game(player1, player2) {
    this.player1 = player1;
    this.player2 = player2;
    this.scorePlayer1 = -1;
    this.scorePlayer2 = -1;
    this.source1 = null;
    this.source2 = null;
    this.number = null;
}

/*
Setzt die Herkunft von Spieler 1 des aktuellen Spiels (von wo kommt Spieler 1, kommt er als Verlierer oder Gewinner?) 
Input:  game: Spiel (Vorgängerspiel)
        asWinner: boolean (hat er im Vorgängerspiel verloren oder gewonnen)
Output: void
*/

Game.prototype.setSourceP1 = function (game, asWinner) {
        this.source1 = new Source(game, asWinner);
    }
    /*
    Setzt die Herkunft von Spieler 2 des aktuellen Spiels (von wo kommt Spieler 2, kommt er als Verlierer oder Gewinner?) 
    Input:  game: Spiel (Vorgängerspiel)
            asWinner: boolean (hat er im Vorgängerspiel verloren oder gewonnen)
    Output: void
    */
Game.prototype.setSourceP2 = function (game, asWinner) {
    this.source2 = new Source(game, asWinner);
}

/*
Gibt den Sieger des gegebenen Spiels zurück
Input: game: Spiel (aus dem der Gewinner ermittelt werden soll
Output: Gewinner: Player
*/
Game.getWinner = function (game) {
    if (game.player1 == -1) {
        return game.player2;
    } else if (game.player2 == -1) {
        return game.player1;
    } else {
        if (game.scorePlayer1 > game.scorePlayer2) {
            return game.player1;
        } else if (game.scorePlayer1 < game.scorePlayer2) {
            return game.player2;
        } else {
            return null;
        }
    }
}

/*
Gibt den Verlierer des gegebenen Spiels zurück
Input: game: Spiel (aus dem der Verlierer ermittelt werden soll
Output: Verlierer: Player
*/
Game.getLoser = function (game) {
    if (game.player1 == -1) {
        return game.player1;
    } else if (game.player2 == -1) {
        return game.player2;
    } else {
        if (game.scorePlayer1 < game.scorePlayer2) {
            return game.player1;
        } else if (game.scorePlayer1 > game.scorePlayer2) {
            return game.player2;
        } else {
            return null;
        }
    }
}

/* Klasse: Source 
    Die Klasse hält die Herkunft eines Spielers
    besitzt die Attribute:
    game: Game
    asWinner: boolean
Der Konstruktor legt ein neues Objekt der Klasser an.
Input: game: Game, asWinner: boolean
*/

function Source(game, asWinner) {
    this.game = game;
    this.asWinner = asWinner;
}


/* Klasse: Tournament
Erzeugt Objekte der klasse Turnier
hier wird das gesamte Turnier gehalten und initial erzeugt. Das Objekt besitzt die folgenden Attribute
    fieldSize: int (Größe des Feldes)
    gameList: Game[] (Array aller Spiele)
    competitorsList: Player[] (Array aller Teilnehmer)
    mainRound: int[]                (Spiele der Hauptrrunde mit verweis auf die Gesamtspielliste)
    winnersbracket: int[]           (Spiele der Gewinnerrunde mit verweis auf die Gesamtspielliste)
    winnersbracketRoundNumber: int  (Anzahl der Runden in der Gewinnerrunde)
    losersbracket: int[]            (Spiele der Verliererrunde mit Verweis auf die Gesamtspielliste)
    losersbracketRoundNumber: int   (Anzahl der Runden in der Verliererrunde)
    final: Spiel                    (das Finalspiel)
    counter: int                    (wird zur Zeit nicht genutzt)

Der Konstruktor erzeugt ein Objekt der Klasse
Input: competitors: Sting[] (Alle teilnehmer als String)
Output: turnier: Turnier
*/


function Tournament(competitors, name) {
    this.fieldSize = Math.pow(2, Math.ceil(Math.log(competitors.length) / Math.log(2)));
    this.gameList = [];
    this.competitorsList = [];
    var numberBye = this.fieldSize - competitors.length;
    for (var i = 0; i < competitors.length; i++) {
        this.competitorsList[this.competitorsList.length] = new Player(competitors[i]);
    }
    this.mainRound = [];
    this.allocationMR(numberBye);
    this.winnersbracket = [];
    this.winnersbracketRoundNumber = null;
    this.allocationWB();
    this.losersbracket = [];
    this.losersbracketRoundNumber = null;
    this.allocationLB();
    this.gameList[this.gameList.length] = new Game(null, null);
    this.final = this.gameList.length - 1;
    this.gameList[this.final].number = 1000;
    this.gameList[this.final].setSourceP1(this.winnersbracket[this.winnersbracket.length - 1], true);
    this.gameList[this.final].setSourceP2(this.losersbracket[this.losersbracket.length - 1], true);
    this.counter = 1;
    this.name = name;
    this.refreshGames();
}

Tournament.prototype.refreshGames = function () {
        for (var i = 0; i < this.gameList.length; i++) {
            if (this.gameList[i].source1 != null) {
                if (this.gameList[i].source1.asWinner) {
                    this.gameList[i].player1 = Game.getWinner(this.gameList[this.gameList[i].source1.game]);
                } else {
                    this.gameList[i].player1 = Game.getLoser(this.gameList[this.gameList[i].source1.game]);
                }
            }
            if (this.gameList[i].source2 != null) {
                if (this.gameList[i].source2.asWinner) {
                    this.gameList[i].player2 = Game.getWinner(this.gameList[this.gameList[i].source2.game]);
                } else {
                    this.gameList[i].player2 = Game.getLoser(this.gameList[this.gameList[i].source2.game]);
                }
            }
        }
    }
    /*
    Verteilung in der Spieler auf die Hauptrunde
    TODO: Verteilung von Freilosen
    */
Tournament.prototype.allocationMR = function (numberBye) {
    var tmpCompetitorsList = [];
    for (var i = 0; i < (this.competitorsList.length); i++) {
        tmpCompetitorsList[i] = i;
    }
    var games = []
    for (var i = 0; i < this.fieldSize / 2; i++) {
        games[i] = new Game(null, null);
        games[i].number = i + 1;
    }
    games = this.allocationBye(games, numberBye, true);

    for (var i = 0; i < games.length; i++) {
        //wenn spieler1 nicht freilos
        if (games[i].player1 != -1) {
            //setze Spieler 1
            var indexS1 = Math.floor(Math.random() * tmpCompetitorsList.length);
            games[i].player1 = tmpCompetitorsList[indexS1];
            tmpCompetitorsList.splice(indexS1, 1);
        }
        //setze Spieler 2
        var indexS2 = Math.floor(Math.random() * tmpCompetitorsList.length);
        games[i].player2 = tmpCompetitorsList[indexS2];
        tmpCompetitorsList.splice(indexS2, 1);
        //Übertragung in Spielliste und hauptrunde
        this.gameList[this.gameList.length] = games[i];
        this.mainRound[i] = this.gameList.length - 1;
    }
}

Tournament.prototype.allocationBye = function (games, numberBye, isTop) {
    if (games.length > 1 && numberBye > 0) {
        if (isTop) {
            var g1 = this.allocationBye(games.slice(0, games.length / 2), Math.ceil(numberBye / 2), true);
            var g2 = this.allocationBye(games.slice(games.length / 2, games.length), Math.floor(numberBye / 2), false);
        } else {
            var g1 = this.allocationBye(games.slice(0, games.length / 2), Math.floor(numberBye / 2), true);
            var g2 = this.allocationBye(games.slice(games.length / 2, games.length), Math.ceil(numberBye / 2), false);
        }
        games = g1.concat(g2);
    } else if (numberBye > 0) {
        games[0].player1 = -1;
        games[0].scorePlayer2 = 1;
        games[0].scorePlayer1 = 0;
    }
    return games;
}

/*
Verteilung in der Gewinnerrunde (das Setzen der Herkunft)
Wird nur intern verwendet und ist daher noch nicht weiter beschrieben
*/
Tournament.prototype.allocationWB = function () {
        for (var i = 0; i < (this.fieldSize / 2 - 1); i++) {
            this.gameList[this.gameList.length] = new Game(null, null);
            this.winnersbracket[i] = this.gameList.length - 1;
            this.gameList[this.winnersbracket[i]].number = i + 1;
        }
        this.winnersbracketRoundNumber = (Math.log((this.winnersbracket.length + 1) / 2) / Math.log(2) + 1);
        for (var i = 0; i < this.mainRound.length; i = i + 2) {
            this.gameList[this.winnersbracket[i / 2]].setSourceP1(this.mainRound[i], true);
            this.gameList[this.winnersbracket[i / 2]].setSourceP2(this.mainRound[i + 1], true);
        }
        for (var x = 1; x < this.winnersbracketRoundNumber; x++) {
            var roundX = Tournament.getWinnersbracketRound(x, this);
            var roundX1 = Tournament.getWinnersbracketRound(x + 1, this);
            for (var i = 0; i < roundX.length; i = i + 2) {
                this.gameList[roundX1[i / 2]].setSourceP1(roundX[i], true);
                this.gameList[roundX1[i / 2]].setSourceP2(roundX[i + 1], true);
            }
        }
    }
    /*
    Verteilung in der Verliererrunde (das Setzen der Herkunft)
    Wird nur intern verwendet und ist daher noch nicht weiter beschrieben
    */
Tournament.prototype.allocationLB = function () {
        for (var i = 0; i < (this.fieldSize - 2); i++) {
            this.gameList[this.gameList.length] = new Game(null, null);
            this.losersbracket[i] = this.gameList.length - 1;
            this.gameList[this.losersbracket[i]].number = i + 1;
        }
        this.losersbracketRoundNumber = Math.floor(Math.log((this.losersbracket.length / 2 + 1) / 2) / Math.log(2) + 1) * 2;
        //Verteilung HR --> VR1
        for (var i = 0; i < this.mainRound.length; i = i + 2) {
            this.gameList[this.losersbracket[i / 2]].setSourceP1(this.mainRound[i], false);
            this.gameList[this.losersbracket[i / 2]].setSourceP2(this.mainRound[i + 1], false);
        }
        //Verteilung VR/GR -- > VR
        for (var x = 1; x < this.losersbracketRoundNumber; x++) {
            if (x % 2 == 0) {
                var roundX = Tournament.getLosersbracketRound(x, this);
                var roundX1 = Tournament.getLosersbracketRound(x + 1, this);
                for (var i = 0; i < roundX.length; i = i + 2) {
                    this.gameList[roundX1[i / 2]].setSourceP1(roundX[i], true);
                    this.gameList[roundX1[i / 2]].setSourceP2(roundX[i + 1], true);
                }
            } else {
                var vrX1 = Tournament.getLosersbracketRound(x + 1, this);
                var vrX = Tournament.getLosersbracketRound(x, this);
                var gr = Tournament.getWinnersbracketRound((x + 1) / 2, this);
                for (var i = 0; i < vrX.length; i++) {
                    this.gameList[vrX1[i]].setSourceP1(vrX[i], true);
                    this.gameList[vrX1[i]].setSourceP2(gr[gr.length - 1 - i], false);
                }
            }
        }
    }
    /*
    Gibt die gewünschte Runde der Verliererrunden des angegebenen Turniers aus
    Input:  i: int (Nummer der Runde, beginned bei 1), tournament: Tournament (Turnier aus dem die Runde ausgegeben werden soll)
    Output: Spiele: Game[]
    */
Tournament.getLosersbracketRound = function (i, tournament) {
        if (i <= tournament.losersbracketRoundNumber) {
            var toGame = 0;
            var fromGame = 0;
            for (var x = 1; x <= i; x++) {
                var tmpX = Math.floor((x + 1) / 2 + 1);
                fromGame = toGame + 1;
                toGame = toGame + Math.floor(tournament.fieldSize / Math.pow(2, tmpX));
            }
            var tmp = [];
            for (var x = 0; x < (toGame - fromGame + 1); x++) {
                tmp[x] = tournament.losersbracket[x + fromGame - 1];
            }
            return tmp;
        } else {
            return null;
        }
    }
    /*
    Gibt die gewünschte Runde der Gewinnerrunden des angegebenen Turniers aus
    Input:  i: int (Nummer der Runde, beginned bei 1), tournament: Tournament (Turnier aus dem die Runde ausgegeben werden soll)
    Output: Spiele: Game[]
    */
Tournament.getWinnersbracketRound = function (i, tournament) {
        if (i <= tournament.winnersbracketRoundNumber) {
            var sumGames = Math.pow(2, tournament.winnersbracketRoundNumber - i);
            var toGame = Math.pow(2, tournament.winnersbracketRoundNumber) * (1 - Math.pow(2, -i));
            var fromGame = toGame - sumGames + 1;
            var tmp = [];
            for (var x = 0; x < sumGames; x++) {
                tmp[x] = tournament.winnersbracket[x + fromGame - 1];
            }
            return tmp;
        } else {
            return null;
        }
    }
    /*
    Setzt das Ergebnis des angegebenen Spiels im angg. Turnier
    und aktualisiert die Folgespiele.
    Input: 
        gameIndex: int (Index des Spiels in der Gesamtspielliste)
        score1: int
        score2: int
        tournament: Tournament
    Ouput: void
    */
Tournament.setRes = function (gameIndex, score1, score2, tournament) {
    if (tournament == undefined ||
        tournament == null ||
        gameIndex < 0 ||
        score1 < 0 ||
        score2 < 0 ||
        tournament.gameList[gameIndex].player1 == null ||
        tournament.gameList[gameIndex].player2 == null ||
        score1 == score2) {
        return false;
    }
    tournament.gameList[gameIndex].scorePlayer1 = score1;
    tournament.gameList[gameIndex].scorePlayer2 = score2;
    for (var i = 0; i < tournament.gameList.length; i++) {
        var tmpGame = tournament.gameList[i];
        if (tmpGame.source1 != null && tmpGame.source1.game == gameIndex) {
            if (tmpGame.source1.asWinner) {
                tmpGame.player1 = Game.getWinner(tournament.gameList[gameIndex]);
            } else {
                tmpGame.player1 = Game.getLoser(tournament.gameList[gameIndex]);
            }
            if (tmpGame.player2 == -1) {
                if (!Tournament.setRes(i, 1, 0, tournament)) {
                    return false;
                }
            }
        } else if (tmpGame.source2 != null && tmpGame.source2.game == gameIndex) {
            if (tmpGame.source2.asWinner) {
                tmpGame.player2 = Game.getWinner(tournament.gameList[gameIndex]);
            } else {
                tmpGame.player2 = Game.getLoser(tournament.gameList[gameIndex]);
            }
            if (tmpGame.player1 == -1) {
                if (!Tournament.setRes(i, 0, 1, tournament)) {
                    return false;
                }
            }
        }
    }
    return true;
}

Tournament.setResAndGetChanges = function (gameIndex, score1, score2, tournament) {
    if (tournament == undefined ||
        tournament == null ||
        gameIndex < 0 ||
        score1 < 0 ||
        score2 < 0 ||
        tournament.gameList[gameIndex].player1 == null ||
        tournament.gameList[gameIndex].player2 == null ||
        score1 == score2) {
        return false;
    }
    var changedGames = [];
    tournament.gameList[gameIndex].scorePlayer1 = score1;
    tournament.gameList[gameIndex].scorePlayer2 = score2;
    changedGames.push({
        index: gameIndex,
        game: tournament.gameList[gameIndex]
    });
    for (var i = 0; i < tournament.gameList.length; i++) {
        var tmpGame = tournament.gameList[i];
        if (tmpGame.source1 != null && tmpGame.source1.game == gameIndex) {
            if (tmpGame.source1.asWinner) {
                tmpGame.player1 = Game.getWinner(tournament.gameList[gameIndex]);
            } else {
                tmpGame.player1 = Game.getLoser(tournament.gameList[gameIndex]);
            }
            changedGames.push({
                index: i,
                game: tmpGame
            });
            if (tmpGame.player2 == -1) {
                var concat = Tournament.setResAndGetChanges(i, 1, 0, tournament);
                if (concat == false) {
                    return false;
                }
                concat.shift();
                changedGames = changedGames.concat(concat);
            }
        } else if (tmpGame.source2 != null && tmpGame.source2.game == gameIndex) {
            if (tmpGame.source2.asWinner) {
                tmpGame.player2 = Game.getWinner(tournament.gameList[gameIndex]);
            } else {
                tmpGame.player2 = Game.getLoser(tournament.gameList[gameIndex]);
            }
            changedGames.push({
                index: i,
                game: tmpGame
            });
            if (tmpGame.player1 == -1) {
                var concat = Tournament.setResAndGetChanges(i, 0, 1, tournament);
                if (concat == false) {
                    return false;
                }
                concat.shift();
                changedGames = changedGames.concat(concat);
            }
        }
    }
    return changedGames;
}